package tokenizer;

import java.io.BufferedReader;
import java.io.Reader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Tokenizer {

	private char c;
	private BufferedReader br;
	private List<Token> t;
	private static ArrayList<Character> OP;
	private StringBuilder sb;

	public Tokenizer() {
	};

	public Tokenizer(Reader in) {
		br = new BufferedReader(in);
		t = new ArrayList<Token>();

		OP = new ArrayList<Character>();
		OP.add('+');
		OP.add('-');
		OP.add('*');
		OP.add('/');
		OP.add('=');
		OP.add('(');
		OP.add(')');

		sb = new StringBuilder();
	}

	public void readToken() throws Exception {

		int read =  br.read();
		while (read != -1) {
				
			c = (char)(read);
			if (isDecimal(c) || isSeparator(c)) {
				addToken(new Token(Token.Type.Num, null, selectDecimal(c)));
			} else if (isOperator(c)) {
				addToken(new Token(selectOperator(c), null, null));
			} else if (isId(c)) {
				addToken(new Token(Token.Type.Id, selectId(c), null));
			} else {

			}
			System.out.println(t);
			read = br.read();
		}
	}

	private void addToken(Token t) {
		this.t.add(t);
	}

	private void removeToken(Token t) {

	}

	private boolean isDecimal(char c) {
		if (Character.isDigit(c)) {
			return true;
		}
		return false;
	}

	private BigDecimal selectDecimal(char c) throws Exception {
		// TODO
		br.mark(2);
		sb.delete(0, sb.length());
		sb.append(c);
		c = (char) br.read();
		while (isDecimal(c)) {
			sb.append(c);
			br.mark(3);
			c = (char) br.read();
		}
		if (isExp(c)){
			StringBuilder sbTemp = new StringBuilder();
			sbTemp.append(c);
			c = (char) br.read();
			if (c == '+' || c == '-'){
				sbTemp.append(c);
				c = (char) br.read();
			}
			while (isDecimal(c)) {
				sbTemp.append(c);
				br.mark(1);
				c = (char) br.read();
			}
			if(sbTemp.length() > 2){
				sb.append(sbTemp.toString());
			}
		}
		br.reset();
		return new BigDecimal(sb.toString());

	}
	
	private String selectId(char c) throws Exception {
		// TODO
		br.mark(2);
		sb.delete(0, sb.length());
		sb.append(c);
		c = (char) br.read();
		while (isId(c)) {
			sb.append(c);
			br.mark(1);
			c = (char) br.read();
		}
		br.reset();
		return sb.toString();

	}

	private boolean isOperator(char c) {
		if (OP.contains(c)) {
			return true;
		}
		return false;
	}

	private Token.Type selectOperator(char c) {

		switch (c) {

		case '+':
			return Token.Type.Plus;
		case '-':
			return Token.Type.Minus;
		case '*':
			return Token.Type.Times;
		case '/':
			return Token.Type.Divide;
		case '(':
			return Token.Type.OPar;
		case ')':
			return Token.Type.CPar;
		case '=':
			return Token.Type.Equal;
		default:
			return null;

		}

	}

	private boolean isId(char c) {

		if (Character.isLetter(c)) {
			return true;
		}
		return false;
	}
	
	private boolean isExp(char c) {

		if (c == 'e' || c == 'E') {
			return true;
		}
		return false;
	}

	public List<Token> getT() {
		return t;
	}

	private boolean isSeparator(char c) {

		if (c == '.') {
			return true;
		}
		return false;
	}

	public void printList(){
		
		Iterator itr = t.iterator();
	      while(itr.hasNext()) {
	         Object element = itr.next();
	         System.out.print(element + " ");
	      }
		
	}
	
}
